package jgl.vajra.kingkong.widget.retrofithelper.utils;

import android.util.Base64;

import javax.crypto.Cipher;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;

public class RSACCoder {

    private static final String KEY_ALGORITHM = "RSA";                //加密算法RSA
    private static final String SIGNATURE_ALGORITHM = "MD5withRSA";   //签名算法
    private static final String randomType = "SHA1PRNG";

    //RSA本身的限制：最大加密明文大小 = 117
    private static final int MAX_ENCRYPT_BLOCK = 117;
    //RSA本身的限制：最大解密密文大小 = keySize / 8 = 128 或 256
    private static final int MAX_DECRYPT_BLOCK = 256;

    private static final int keysize = 2048;

    private static final byte[] seedbyte = "d2~d䤙94!8f1鯯6891譇48=6a䮚b3b5鐕a6bf#f3륉77%7^20.e".getBytes(StandardCharsets.UTF_8);

    private enum KeyType {
        PUBLIC_KEY, PRIVATE_KEY
    }


    /**
     * 生成私有和公有密钥
     */
    public static Map<Integer, String> genKeyPair() throws Exception {

        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(KEY_ALGORITHM);

        //keyPairGenerator.initialize(512);
        //SecureRandom random = new SecureRandom();
        //long rang = RandomUtil.randomLong(1223000000000000000L, 9223000000000000000L);

        SecureRandom random = SecureRandom.getInstance(randomType);
        random.setSeed(seedbyte);
        keyPairGenerator.initialize(keysize, random);
        KeyPair keyPair = keyPairGenerator.generateKeyPair();

        //byte[] bytes = keypairToBin(keyPair);
        //String secretString = Base64.encodeBase64String(bytes);
        //byte[] bytes = Base64.decodeBase64(ddd);
        //KeyPair keyPair = binToKeypair(bytes);
        //System.out.println("KeyPair对像 : "+ keyPair.toString());

        RSAPrivateKey rsaprivateKey = (RSAPrivateKey)keyPair.getPrivate();                //私有密钥
        RSAPublicKey rsapublicKey = (RSAPublicKey)keyPair.getPublic();                    //公有密钥

        Map<Integer, String> keyMap = new HashMap<>();
        keyMap.put(1, Base64.encodeToString(rsaprivateKey.getEncoded(), Base64.NO_WRAP));
        keyMap.put(2, Base64.encodeToString(rsapublicKey.getEncoded(), Base64.NO_WRAP));
        //Base64.decodeBase64(Base64.encodeBase64String(rsaprivateKey.getEncoded()))

        System.out.println("privateKey : " + keyMap.get(1));
        System.out.println("publicKey : " + keyMap.get(2));

        return keyMap;
    }

    //---------------------------------------------------------------------------------------------------
    /**
     * 私钥加密，公钥解密--加密
     * 对于给定生成的不同密钥，得到的摘要消息会不同，所以在实际应用中，要保存我们的密钥
     */
    public static String encoderRSAPrivateKey(String rsaprivateKey, String src) throws Exception {
        //PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(rsaprivateKey.getEncoded());

        byte[] data = src.getBytes(StandardCharsets.UTF_8);

        PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(Base64.decode(rsaprivateKey, Base64.NO_WRAP));
        KeyFactory privateKeyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        PrivateKey privateKey = privateKeyFactory.generatePrivate(pkcs8EncodedKeySpec);
        Cipher privateCipher = Cipher.getInstance(KEY_ALGORITHM);
        privateCipher.init(Cipher.ENCRYPT_MODE, privateKey);
        byte[] result = privateCipher.doFinal(src.getBytes());
        //System.out.println("私钥加密，公钥解密--加密:" + Base64.encodeBase64String(result));
        return Base64.encodeToString(result, Base64.NO_WRAP);
    }

    /**
     * 私钥加密，公钥解密--解密
     * 对于给定生成的不同密钥，得到的摘要消息会不同，所以在实际应用中，要保存我们的密钥
     */
    public static String decoderRSApublicKey(String rsapublicKey, String src){
        byte[] result;
        try {
            X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(Base64.decode(rsapublicKey, Base64.NO_WRAP));
            KeyFactory publicKeyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
            PublicKey publicKey = publicKeyFactory.generatePublic(x509EncodedKeySpec);
            Cipher publicCipher = Cipher.getInstance(KEY_ALGORITHM);
            publicCipher.init(Cipher.DECRYPT_MODE, publicKey);
            result = publicCipher.doFinal(Base64.decode(src, Base64.NO_WRAP));
        } catch (Exception e) {
            result = null;
        }
        if (result == null) result = "".getBytes(StandardCharsets.UTF_8);
        return new String(result);
    }
    //--------------------------------------------------------------------------------------------------------------------

    /**
     * 公钥加密，私钥解密---加密
     * 对于给定生成的不同密钥，得到的摘要消息会不同，所以在实际应用中，要保存我们的密钥
     */
    public static String encoderRSApublicKey(String rsapublicKey, String src) throws Exception {

        byte[] data = src.getBytes(StandardCharsets.UTF_8);

        X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(Base64.decode(rsapublicKey, Base64.NO_WRAP));
        KeyFactory publicKeyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        PublicKey publicKey = publicKeyFactory.generatePublic(x509EncodedKeySpec);
        Cipher publicCipher = Cipher.getInstance(KEY_ALGORITHM);
        publicCipher.init(Cipher.ENCRYPT_MODE, publicKey);
        byte[] result = publicCipher.doFinal(src.getBytes());
        String encoderSrc = Base64.encodeToString(result, Base64.NO_WRAP);
        //System.out.println("公钥加密，私钥解密---加密:" + Base64.encodeBase64String(result));
        return encoderSrc;
    }

    /**
     * 公钥加密，私钥解密---解密
     * 对于给定生成的不同密钥，得到的摘要消息会不同，所以在实际应用中，要保存我们的密钥
     */
    public static String decoderRSAPrivateKey(String rsaprivateKey, String src) throws Exception {

        byte[] data = src.getBytes(StandardCharsets.UTF_8);

        PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(Base64.decode(rsaprivateKey, Base64.NO_WRAP));
        KeyFactory privateKeyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        PrivateKey privateKey = privateKeyFactory.generatePrivate(pkcs8EncodedKeySpec);
        Cipher privateCipher = Cipher.getInstance(KEY_ALGORITHM);
        privateCipher.init(Cipher.DECRYPT_MODE, privateKey);
        byte[] result = privateCipher.doFinal(Base64.decode(src, Base64.NO_WRAP));
        //System.out.println("公钥加密，私钥解密---解密:" + new String(result));
        //String decoderSrc = new String(result);
        return new String(result);
    }

    public static byte[] keypairToBin(KeyPair kp){
        try (ByteArrayOutputStream bout = new ByteArrayOutputStream(); ObjectOutputStream oout = new ObjectOutputStream(bout);) {
            oout.writeObject(kp);
            return bout.toByteArray();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    public static KeyPair binToKeypair(byte[] data){
        try (ByteArrayInputStream b = new ByteArrayInputStream(data); ObjectInputStream o = new ObjectInputStream(b);) {
            Object obj =o.readObject();
            return((KeyPair)obj);
        }catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

}
